﻿// ------------------------------------------------------------------------
// 项目名称：Canroc.Net 
// 版权归属：Canroc（https://gitee.com/canroc）
//
// 许可证信息
// Canroc.Net项目主要遵循 Apache 许可证（版本 2.0）进行分发和使用。许可证位于源代码树根目录中的 LICENSE-APACHE 文件。
//
// 使用条款：
// 1.使用本项目应遵守相关法律法规和许可证的要求。
// 2.不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动。
// 3.任何基于本项目二次开发而产生的一切法律纠纷和责任，我们不承担任何责任
//
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
//
// 其他重要信息
// Canroc.Net 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// ------------------------------------------------------------------------

using StackExchange.Redis;

namespace Canroc.Net.SystemService.RedisService.Impl;

/// <summary>
///     Redis服务
/// </summary>
public class RedisService(ConnectionMultiplexer redis) : IRedisService
{
    #region Base

    /// <summary>
    ///     判断Key值是否存在
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public async Task<bool> ExistsAsync(string key)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.KeyExistsAsync($"{redisOptions.Prefix}{key}");
    }

    /// <summary>
    ///     key重命名
    /// </summary>
    /// <param name="key"></param>
    /// <param name="newKey"></param>
    /// <returns></returns>
    public async Task<bool> KeyRenameAsync(string key, string newKey)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.KeyRenameAsync($"{redisOptions.Prefix}{key}", $"{redisOptions.Prefix}{newKey}");
    }

    /// <summary>
    ///     设置缓存过期
    /// </summary>
    /// <param name="key"></param>
    /// <param name="datetime"></param>
    public async Task<bool> SetExpireAsync(string key, DateTime datetime)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.KeyExpireAsync($"{redisOptions.Prefix}{key}", datetime);
    }

    /// <summary>
    ///     删除key值
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public async Task<bool> DeleteAsync(string key)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.KeyDeleteAsync($"{redisOptions.Prefix}{key}");
    }

    /// <summary>
    ///     清除所有缓存
    /// </summary>
    /// <returns></returns>
    public async Task<int> DeleteAll()
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        var server = redis.GetServer(redis.GetEndPoints().First());

        var list = server.Keys(pattern: $"{redisOptions.Prefix}*").Select(u => u.ToString()).ToList();
        list.ForEach(key =>
        {
            db.KeyDelete(key);
        });

        return await Task.FromResult(list.Count);
    }

    /// <summary>
    ///     获取第一个键
    /// </summary>
    /// <returns></returns>
    public async Task<string> GetFirstKeyAsync()
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var server = redis.GetServer(redis.GetEndPoints().First());
        var list = server.Keys(pattern: $"{redisOptions.Prefix}*")
            .Select(u => u.ToString().Replace(redisOptions.Prefix, "")).ToList();
        if (list.Count == 0)
        {
            return string.Empty;
        }

        list.Sort();
        return await Task.FromResult(list.First());
    }

    /// <summary>
    ///     获取所有的Key值
    /// </summary>
    /// <returns></returns>
    public async Task<List<string>> GetAllKeyAsync()
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var server = redis.GetServer(redis.GetEndPoints().First());
        var list = server.Keys(pattern: $"{redisOptions.Prefix}*")
            .Select(u => u.ToString().Replace(redisOptions.Prefix, "")).ToList();
        list.Sort();
        return await Task.FromResult(list);
    }

    /// <summary>
    ///     获取第一个键(按照pattern匹配获取)
    /// </summary>
    /// <returns></returns>
    public async Task<string> GetFirstKeyAsync(string pattern)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var server = redis.GetServer(redis.GetEndPoints().First());
        var list = server.Keys(pattern: $"{redisOptions.Prefix}{pattern}*")
            .Select(u => u.ToString().Replace(redisOptions.Prefix, ""))
            .ToList();
        if (list.Count == 0)
        {
            return string.Empty;
        }

        list.Sort();
        return await Task.FromResult(list.First());
    }

    /// <summary>
    ///     获取所有的Key值(按照pattern匹配获取)
    /// </summary>
    /// <returns></returns>
    public async Task<List<string>> GetAllKeyAsync(string pattern)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var server = redis.GetServer(redis.GetEndPoints().First());
        var list = server.Keys(pattern: $"{redisOptions.Prefix}{pattern}*")
            .Select(u => u.ToString().Replace(redisOptions.Prefix, ""))
            .ToList();
        list.Sort();
        return await Task.FromResult(list);
    }

    #endregion

    #region String

    /// <summary>
    ///     添加对象
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    /// <param name="key">键</param>
    /// <param name="obj">值</param>
    /// <param name="expire">过期时间，单位：分钟</param>
    /// <returns></returns>
    public async Task<bool> StringSetAsync<T>(string key, T obj, TimeSpan? expire = null)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.StringSetAsync($"{redisOptions.Prefix}{key}", JsonSerializer.Serialize(obj), expire);
    }

    /// <summary>
    ///     批量添加
    /// </summary>
    /// <param name="keys">键</param>
    /// <param name="values">值</param>
    /// <returns></returns>
    public async Task<bool> StringSetAsync(string[] keys, string[] values)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        var count = keys.Length;
        var keyValuePair = new KeyValuePair<RedisKey, RedisValue>[count];
        for (var i = 0; i < count; i++)
        {
            keyValuePair[i] = new KeyValuePair<RedisKey, RedisValue>($"{redisOptions.Prefix}{keys[i]}", values[i]);
        }

        return await db.StringSetAsync(keyValuePair);
    }

    /// <summary>
    ///     获取多个
    /// </summary>
    /// <param name="keys">键</param>
    /// <returns></returns>
    public async Task<string?[]> StringGetAsync(string[] keys)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        var redisKeys = keys.Select(redisKey => (RedisKey)$"{redisOptions.Prefix}{redisKey}").ToArray();
        var redisValues = await db.StringGetAsync(redisKeys);

        return redisValues.ToStringArray();
    }

    /// <summary>
    ///     获取对象
    /// </summary>
    /// <typeparam name="T">类型</typeparam>
    /// <param name="key">键</param>
    /// <returns></returns>
    public async Task<T?> StringGetAsync<T>(string key)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        var value = await db.StringGetAsync($"{redisOptions.Prefix}{key}");
        return JsonSerializer.Deserialize<T>(value!);
    }

    #endregion

    #region List

    /// <summary>
    ///     移除并返回存储在该键列表的第一个元素
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public async Task<T?> ListLeftPopAsync<T>(string key)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        var values = await db.ListLeftPopAsync($"{redisOptions.Prefix}{key}");
        return JsonSerializer.Deserialize<T>(values!);
    }

    /// <summary>
    ///     移除并返回存储在该键列表的最后一个元素
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public async Task<T?> ListRightPopAsync<T>(string key)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        var value = await db.ListRightPopAsync($"{redisOptions.Prefix}{key}");
        return JsonSerializer.Deserialize<T>(value!);
    }

    /// <summary>
    ///     将值插入到key值的最左边
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public async Task<long> ListLeftPushAsync<T>(string key, T value)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.ListLeftPushAsync($"{redisOptions.Prefix}{key}", JsonSerializer.Serialize(value));
    }

    /// <summary>
    ///     将值插入到key值的最右边
    /// </summary>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <returns></returns>
    public async Task<long> ListRightPushAsync<T>(string key, T value)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.ListRightPushAsync($"{redisOptions.Prefix}{key}", JsonSerializer.Serialize(value));
    }

    /// <summary>
    ///     返回列表长度
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public async Task<long> ListLengthAsync(string key)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.ListLengthAsync($"{redisOptions.Prefix}{key}");
    }

    /// <summary>
    ///     获取key值上的第一个数据
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="key"></param>
    /// <returns></returns>
    public async Task<T?> ListGetByIndexAsync<T>(string key)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        var values = await db.ListGetByIndexAsync($"{redisOptions.Prefix}{key}", 0);
        return JsonSerializer.Deserialize<T>(values!);
    }

    /// <summary>
    ///     返回在该列表上键所对应的元素
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public async Task<List<T>> ListGetAll<T>(string key)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        List<T> result = [];
        var list = await db.ListRangeAsync($"{redisOptions.Prefix}{key}");
        result.AddRange(list.Select(value => JsonSerializer.Deserialize<T>(value!)).OfType<T>());

        return result;
    }

    #endregion

    #region Hash

    /// <summary>
    ///     判断某个数据是否已经被缓存
    /// </summary>
    public async Task<bool> HashExistsAsync(string key, string hashId)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.HashExistsAsync($"{redisOptions.Prefix}{key}", hashId);
    }

    /// <summary>
    ///     存储数据到hash表
    /// </summary>
    public async Task<bool> HashSetAsync<T>(string key, string hashId, T value)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.HashSetAsync($"{redisOptions.Prefix}{key}", hashId, JsonSerializer.Serialize(value));
    }

    /// <summary>
    ///     移除hash中的某值
    /// </summary>
    public async Task<bool> HashDeleteAsync(string key, string hashId)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.HashDeleteAsync($"{redisOptions.Prefix}{key}", hashId);
    }

    /// <summary>
    ///     从hash表获取数据
    /// </summary>
    public async Task<T?> HashGetAsync<T>(string key, string hashId)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        var value = await db.HashGetAsync($"{redisOptions.Prefix}{key}", hashId);
        return value.HasValue ? JsonSerializer.Deserialize<T>(value!) : default;
    }

    /// <summary>
    ///     获取整个hash的数据
    /// </summary>
    public async Task<Dictionary<string, T>?> HashGetAllAsync<T>(string key)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        Dictionary<string, T> result = new();
        var list = await db.HashGetAllAsync($"{redisOptions.Prefix}{key}");
        if (list.Length == 0)
        {
            return null;
        }

        _ = list.ToList().OrderBy(l => l.Name);
        foreach (var hashValue in list)
        {
            var obj = JsonSerializer.Deserialize<T>(hashValue.Value!);
            if (obj is not null)
            {
                result.Add(hashValue.Name!, obj);
            }
        }

        return result;
    }

    #endregion

    #region Sorted Set

    /// <summary>
    ///     存储数据到sorted set表
    /// </summary>
    public async Task<bool> SortedSetAddAsync<T>(string key, T value, double score)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.SortedSetAddAsync($"{redisOptions.Prefix}{key}", JsonSerializer.Serialize(value), score);
    }

    /// <summary>
    ///     移除min和max之间的所有元素
    /// </summary>
    /// <returns></returns>
    public async Task<long> SortedSetRemoveRangeByScoreAsync(string key, double min, double max)
    {
        var redisOptions = App.GetOptions<RedisOption>();
        var db = redis.GetDatabase(redisOptions.DbIndex);
        return await db.SortedSetRemoveRangeByScoreAsync($"{redisOptions.Prefix}{key}", min, max);
    }

    #endregion
}